#include "Entity3D.hpp"
#include "../ResourceManagers/Mesh3D.hpp"
#include "../ResourceManagers/TextureManager.hpp"
#include "../ResourceManagers/TextureObject.hpp"
#include "../Collisions/BoundingBox.hpp"
#include "../Collisions/BoundingSphere.hpp"
#include "../MessageDispatcher.hpp"
#include "../MMessage.hpp"
#include "../Extensions/ExtensionsLoader.hpp"
#include <iostream>

using namespace std;

Entity3D::Entity3D(string modelName, string textureName)
{
	m_texName = textureName;
	m_pMesh = new Mesh3D(modelName);

	float max_x, max_y, max_z, min_x, min_y, min_z;
	max_x = m_pMesh->getMaximum(X_AXIS);
	max_y = m_pMesh->getMaximum(Y_AXIS);
	max_z = m_pMesh->getMaximum(Z_AXIS);

	min_x = m_pMesh->getMinimum(X_AXIS);
	min_y = m_pMesh->getMinimum(Y_AXIS);
	min_z = m_pMesh->getMinimum(Z_AXIS);

	MVector3D* pCorners = new MVector3D[8];
	pCorners[0].Set(min_x, min_y, min_z);
	pCorners[1].Set(min_x, min_y, max_z);
	pCorners[2].Set(min_x, max_y, max_z);
	pCorners[3].Set(min_x, max_y, min_z);

	pCorners[4].Set(max_x, min_y, min_z);
	pCorners[5].Set(max_x, min_y, max_z);
	pCorners[6].Set(max_x, max_y, max_z);
	pCorners[7].Set(max_x, max_y, min_z);

	m_pBV = new BoundingBox(pCorners);

	TextureManager::GetInstance()->LoadTexture(m_texName);
}

Entity3D::Entity3D(char* pDataBuffer, int iBufferSize, string textureName)
{
	m_texName = textureName;//"mechadog.png";
	m_pMesh = new Mesh3D(pDataBuffer, iBufferSize);

	TextureManager::GetInstance()->LoadTexture(m_texName);
}

Entity3D::~Entity3D()
{
	delete m_pMesh; m_pMesh = NULL;
	delete m_pBV; m_pBV = NULL;
	TextureManager::GetInstance()->UnloadTexture(m_texName);
}

void Entity3D::render()
{
//#define _DEBUG_SBV
	//cout << "entity rendering" <<endl;
	glPushMatrix();
	glTranslatef(getPosition().x, getPosition().y, getPosition().z);
#ifdef _DEBUG_SBV
	glutWireSphere(this->generateBSV()->getRadius(), 10, 10);
#endif // _DEBUG_SBV

#ifdef _DEBUG_BBV
	glutWireCube(this->generateBSV()->getRadius());
#endif // _DEBUG_BBV

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, ((TextureObject*)(TextureManager::GetInstance()->GetTexture(m_texName)))->GetTextureID());
	ExtensionsLoader::glActiveTextureARB(GL_TEXTURE0_ARB);
	m_pMesh->render();
	glPopMatrix();
	glDisable(GL_TEXTURE_2D);
}

const Mesh3D* Entity3D::getMesh() const
{
	return m_pMesh;
}

BoundingBox* Entity3D::getBBox()
{
	m_pBV->invalidateBV(m_translation);
	return m_pBV;
}

BoundingSphere* Entity3D::generateBSV()
{
	MVector3D pos = const_cast<MVector3D&>(getPosition());
	MVector3D maxPoint = MVector3D(m_pMesh->getMaximum(X_AXIS), m_pMesh->getMaximum(Y_AXIS), m_pMesh->getMaximum(Z_AXIS));
	MVector3D minPoint = MVector3D(m_pMesh->getMinimum(X_AXIS), m_pMesh->getMinimum(Y_AXIS), m_pMesh->getMinimum(Z_AXIS));
	MVector3D radiusVec = maxPoint - minPoint;
	float radius = /*m_pMesh->getMaximum(X_AXIS);*/ (radiusVec.GetLength()/3) * 0.75;
	BoundingSphere* pBSV = new BoundingSphere(pos, radius);

	return pBSV;
}

void Entity3D::invalidatePositionChange()
{
	m_pBV->invalidateBV(const_cast<MVector3D&>(getPosition()));
}

bool Entity3D::queryCollision(Entity3D *pCollEntity)
{
	bool bColliding = false;

	BoundingSphere* pOwnBSV = generateBSV();
	BoundingSphere* pIncomingBSV = pCollEntity->generateBSV();

	if(pOwnBSV->queryCollision(pIncomingBSV))
	{
		handleCollision();
		MMessage* pMsg1 = new MMessage(MSG_CMD_HANDLE_COLL, 0, NULL);
		MessageDispatcher::getInstance()->dispatchMessage(pMsg1, getEntityID(), pCollEntity->getEntityID());

		MMessage* pMsg2 = new MMessage(MSG_CMD_HANDLE_COLL, 0, NULL);
		MessageDispatcher::getInstance()->dispatchMessage(pMsg2, getEntityID(), getEntityID());

		bColliding = true;
	}

	return bColliding;
}

void Entity3D::handleCollision()
{
}

//EOF
